/* 三国战记整合脚本(UTF-8 with BOM),尝试先选人
  功能根据各人不同,比较复杂.
  支持fbas模拟器和游聚平台
  
  By setycyas @2023-01-01 22:44
*/

/* 全局设置,库调用,全局量定义
*/ {
  ;** 全局设置
  #NoEnv
  #Warn
  #MaxThreadsPerHotkey 1
  SendMode Event
  SetWorkingDir %A_ScriptDir%

  ;** 库调用
  #Include ..\MyAhkModules\MyKey.ahk ;按键相关库,所有导出函数以MyKey_开头
  ;#Include ..\MyAhkModules\MyXZone.ahk ;导入自定义的游聚平台通用快捷键,用MyXZone_setHotkeys()函数设置
  #Include ..\MyAhkModules\MyFaceDetector.ahk ;方向检测,用MyFaceDetector_setup()函数设置

  ;** 常量,全体大写
  global GAME_NAME := "三国战记" ;用于在Gui中显示游戏名字
  global KEY_A := "x", KEY_B := "e", KEY_C := "d", KEY_D := "s", MACRO_ABC := "a", MACRO_AB_XZONE := "p" ;按键设置
  ;角色名字表
  global NAME_TABLE := {"关羽": "GUANYU", "张飞": "ZHANGFEI", "赵云": "ZHAOYUN", "黄忠": "HUANGZHONG", "马超": "MACHAO"}
  NAME_TABLE["魔法张飞"] := "MOZHANG", NAME_TABLE["诸葛亮"] := "ZHUGELIANG", NAME_TABLE["张辽"] := "ZHANGLIAO"
  NAME_TABLE["貂蝉"] := "DIAOCHAN", NAME_TABLE["白甲黄忠"] := "BAIHUANG"
  
  ;** 枚举量
  global LV_LOW := 0, LV_HIGH := 1 ;枚举等级高低
  global W_AUTOFIRE := 0, W_SPECIAL := 1, W_SINGLE := 2 ;w键的攻击类型

  ;** 全局变量
  ;* 绑定到gui组件的全局变量,以G开头
  global GexeTitle := "" ;游戏平台选择
  global GsbText := "" ;状态栏文本
  global Grole := "" ;角色选择,中文名
  global GwType := "一般连发" ;连发类型,特殊连发是为了让关羽之类过于容易误发下前a的降低误发率而设计的
  global GtestParam1 := 200, GtestParam2 := 200, GtestParam3 := 150 ;测试参数
  ;* 一般全局变量
  global roleEnglish := "" ;选择角色的英文(拼音)名,在NAME_TABLE中对应
  global isAutoFire := +1 ;是否开启连发,+1表示开启
  global lv := LV_LOW ;等级高低
  global wType := W_AUTOFIRE ;攻击键w的枚举类型

}

/* 自定义函数,除Gui设置,Gui响应和热键绑定专用函数以外
*/ {
  
  ;** 缩短MyKey模块的函数名称
  press(key, pressDuration := 100){ 
    return MyKey_press(key, pressDuration)
  }
  pressKeys(keys, delays, duration := 50){
    return MyKey_pressKeys(keys, delays, duration)
  }
  waitKeyUp(key, waitTime, waitDuration := 100){
    return MyKey_waitKeyUp(key, waitTime, waitDuration)
  }
  inputSkill(keys, delays){
    return MyKey_inputSkill(keys, delays)
  }
  autoFire(fireKey, autoFireKey, duration := 50, delay := 50){
    return MyKey_normalAutoFire(fireKey, autoFireKey, duration, delay)
  }

  ;** 刷新状态栏
  refreshSB(){
    local text1 := Grole
    ;连发情况
    switch (wType) {
      case W_AUTOFIRE: {
        text1 := text1 . " , 一般连发"
      } case W_SPECIAL: {
        text1 := text1 . " , 特殊连发"
      } case W_SINGLE: {
        text1 := text1 . " , 单发"
      }
    }
    ;等级情况
    if (lv == LV_LOW)
      text1 := text1 . ", 低等级"
    else
      text1 := text1 . ", 高等级"
    GuiControl, mainUI:Text, GsbText, %text1%
  }

  ;** 游戏操作相关函数
  ;6a
  rSkill(key := 0){
    local direction := MyFaceDetector_getFace()
    pressKeys([direction, KEY_A], [20])
    sleep, 20
    if (key != 0) {
      autoFire(KEY_A, key)
    }
  }

  ;26a或24a
  drSkill(key := 0){
    local direction := MyFaceDetector_getFace()
    inputSkill(["down", direction, KEY_A], [30, 30, 30])
    sleep, 30
    if (key != 0) {
      autoFire(KEY_A, key)
    }
  }

  ;46a或64a
  lrSkill(key := 0){
    local direction2 := MyFaceDetector_getFace()
    local direction1 := (direction2 == "right") ? ("left") : ("right")
    press(direction1, 50)
    sleep, 50
    pressKeys([direction2, KEY_A], [30])
    if (key != 0) {
      autoFire(KEY_A, key)
    }
  }

  ;82a
  udSkill(key := 0){
    press("up", 50)
    sleep, 50
    pressKeys(["down", KEY_A], [30])
    if (key != 0) {
      autoFire(KEY_A, key)
    }
  }
  ;82a,赵云专用按住key可蓄力
  udSkill_zhaoyun(key){
    press("up", 50)
    sleep, 50
    send, {down down}
    sleep, 30
    send, {%KEY_A% down}
    sleep, 50
    send, {down up}
    while (GetKeyState(key)) {
      sleep, 50
    }
    send, {%KEY_A% up}
  }

  ;28a
  duSkill(key := 0){
    press("down", 50)
    sleep, 50
    pressKeys(["up", KEY_A], [30])
    if (key != 0) {
      autoFire(KEY_A, key)
    }
  }

  ;22a
  ddSkill(){
    press("down", 50)
    sleep, 50
    pressKeys(["down", KEY_A], [30])
  }

  ;蹲下,攻击,站起,起身的延时各人可能不同,设定为参数.如standDelay为0则不站起
  squatHit(standDelay := 400){
    send, {down down}
    sleep, 20
    send, {%KEY_B% down}
    sleep, 50
    send, {down up}{%KEY_B% up}
    sleep, 50
    press(KEY_A, 30)
    if (standDelay != 0){
      sleep, %standDelay%
      press(KEY_B, 30)
    }
  }

  ;冲跑,测试发现原地起跑成功率很低,但向该方向移动或出招后成功率会提高很多,感觉是系统判断方式问题.
  dash(){
    local direction := MyFaceDetector_getFace()
    press(direction, 30)
    sleep, 50
    press(direction, 100)
  }

  ;冲跑攻击,当前参数用在张飞10级以上的连击中还可以,参数为延迟攻击毫秒数
  dashAt(atkDelay := 50){
    local direction := MyFaceDetector_getFace()
    press(direction, 30)
    sleep, 50 ;测试发现这里不要超过50
    send, {%direction% down}
    sleep, %atkDelay%
    send, {%KEY_A% down}
    sleep, 50
    send, {%KEY_A% up}
    sleep, 50
    send, {%direction% up}
    sleep, 200
  }
  ;尝试连按三下前冲跑攻击,在连招中还是不行,不过作为起手成功率要高一些
  dashAt2(){
    local direction := MyFaceDetector_getFace()
    press(direction, 30)
    sleep, 30
    press(direction, 30)
    sleep, 30
    press(direction, 30)
    sleep, 50
    press(KEY_A)
  }

  ;后转再反过来冲跑攻击,当前参数在白甲黄忠10级以上连击中不错
  backDashAt(){
    local direction := MyFaceDetector_getFace()
    local backDirection := (direction == "right") ? ("left") : ("right")
    press(backDirection, 50)
    sleep, 50
    press(direction, 50)
    sleep, 50
    send, {%direction% down}
    sleep, 40
    send, {%KEY_A% down}
    sleep, 50
    send, {%KEY_A% up}
    sleep, 100
    send, {%direction% up}
    sleep, 200
  }
  ;4646a,据说也可以!?魔法张飞0-4级可用,5-25级需要先撞上再用!比直接466a好不会出狂风式
  backDashAt2(){
    local direction := MyFaceDetector_getFace()
    local backDirection := (direction == "right") ? ("left") : ("right")
    press(backDirection, 20)
    sleep, 20
    press(direction, 20)
    sleep, 20
    press(backDirection, 20)
    sleep, 20
    press(direction, 20)
    sleep, 40
    press(KEY_A)
  }

  ;一键转身攻击,含上下键,按住连发.测试发现用在魔法张飞的连击中是OK的,不过操作时机也比较难
  backTurnAt(key){
    local direction := MyFaceDetector_getFace()
    local backDirection := (direction == "right") ? ("left") : ("right")
    press(backDirection, 30)
    sleep, 20
    press(direction, 30)
    sleep, 20
    send, {down down}
    sleep, 20
    press(Key_A, 20)
    send, {down up}
    while (GetKeyState(key)) {
      sleep, 20
      press(Key_A, 30)
    }
    sleep, 200
  }

  ;按住key打出白甲黄忠的高等级完整连击的前3段,aaa->撞->a连砍
  fullHit_baihuang(key){
    ;aaa
    loop, 2 {
      press(KEY_A, 20)
      sleep, 120
      if (!GetKeyState(key))
        return
    }
    press(KEY_A, 20)
    ;撞
    if (waitKeyUp(key, 600, 30))
      return
    dashAt(30)
    ;a连击直到放手
    while (GetKeyState(key)) {
      press(KEY_A, 20)
      sleep, 20
    }
    ;断尾
    sleep, 200
  }
  
  ;按住key打出两张飞的高等级完整连击的前3段,连砍和冲撞再连砍,最后的转身另外手动做
  fullHit_zhangfei(key){
    ;aaa
    loop, 2 {
      press(KEY_A, 20)
      sleep, 120
      if (!GetKeyState(key))
        return
    }
    press(KEY_A, 20)
    ;撞
    if (waitKeyUp(key, 630, 30))
      return
    dashAt(20)
    ;a连击直到放手
    ;sleep, 20
    while (GetKeyState(key)) {
      press(KEY_A, 20)
      sleep, 20
    }
    ;断尾
    sleep, 200
  }

  ;按住key打出张辽的完整连击前3段,aaa->蹲a->站起连续a
  fullHit_zhangliao(key){
    ;aaa
    loop, 2 {
      press(KEY_A, 20)
      sleep, 120
      if (!GetKeyState(key))
        return
    }
    press(KEY_A, 20)
    ;蹲a
    if (waitKeyUp(key, 560, 30))
      return
    squatHit(80)
    ;aaaa
    sleep, 175
    press(KEY_B, 20)
    while (GetKeyState(key)) {
      press(KEY_A, 20)
      sleep, 20
    }
    ;断尾
    sleep, 200
  }
  
  ;按住key打出马超的完整连击前3段,aaa->蹲a->站起连a
  fullHit_machao(key){
    ;aaa
    loop, 2 {
      press(KEY_A, 20)
      sleep, 120
      if (!GetKeyState(key))
        return
    }
    press(KEY_A, 20)
    ;蹲a
    if (waitKeyUp(key, 370, 30))
      return
    squatHit(120)
    ;aaaa
    sleep, 200
    press(KEY_B, 20)
    while (GetKeyState(key)) {
      press(KEY_A, 20)
      sleep, 20
    }
    ;断尾
    sleep, 200
  }

  ;按住key打出诸葛亮的完整连击前3段,aa->蹲a->连续a,目前参数打夏侯渊还行,曹操可不行.参数差异较大,不知是不是等级的关系.反正打曹操不可行,就用
  ;夏侯渊的参数好了
  fullHit_zhugeliang(key){
    ;aa
    press(KEY_A, 20)
    if (!GetKeyState(key))
      return
    sleep, 50
    press(KEY_A, 20)
    if (!GetKeyState(key))
      return
    ;蹲a
    sleep, 800
    if (!GetKeyState(key))
      return
    squatHit(0)
    ;aaa
    sleep, 140
    press(KEY_B, 20)
    while (GetKeyState(key)) {
      press(KEY_A, 20)
      sleep, 20
    }
    ;断尾
    sleep, 200
  }

}

/* 设置Gui与Gui响应
*/ {

  ;** 生成Gui
  ;选择游戏平台与角色的Gui
  configGui(){ 
    Gui, configUI:New, , 选择平台与角色
    Gui, configUI:add, Text, ,选择游戏平台:
    Gui, configUI:add, ListBox, vGexeTitle choose1, fbas.exe|X-Zone.exe
    Gui, configUI:add, Text, ,选择角色:
    Gui, configUI:add, ComboBox, vGrole choose2, 关羽|张飞|赵云|黄忠|马超|魔法张飞|诸葛亮|张辽|貂蝉|白甲黄忠
    Gui, configUI:add, Button, gButtonConfigSubmit, 选择
    Gui, configUI:add, Button, xp+100 gButtonExit, 退出
    Gui, configUI:show, w200
  }    
  ;生成主Gui
  mainGui() {
    Gui, mainUI:New, , % SubStr(GexeTitle, 1, 1) . GAME_NAME
    Gui, mainUI:Add, Text, x+20 y+20, GtestParam1： ;
    Gui, mainUI:Add, Edit, xp+80 yp-3 W60 vGtestParam1, %GtestParam1% ;测试参数1
    Gui, mainUI:Add, Text, xp-80 yp+30, GtestParam2： ;
    Gui, mainUI:Add, Edit, xp+80 yp-3 W60 vGtestParam2, %GtestParam2% ;测试参数2
    Gui, mainUI:Add, Text, xp-80 yp+30, GtestParam3： ;
    Gui, mainUI:Add, Edit, xp+80 yp-3 W60 vGtestParam3, %GtestParam3% ;测试参数3
    Gui, mainUI:Add, Text, xp-80 yp+30, 重选人物： ;
    Gui, mainUI:Add, ComboBox, xp+80 yp-3 W100 vGrole choose2, 关羽|张飞|赵云|黄忠|马超|魔法张飞|诸葛亮|张辽|貂蝉|白甲黄忠
    Gui, mainUI:Add, Text, xp-80 yp+30, w键类型： ;
    Gui, mainUI:Add, ComboBox, xp+80 yp-3 W100 vGwType choose1, 一般连发|特殊连发|单发
    Gui, mainUI:Add, Button, xp-80 yp+30 gButtonMainSubmit, 提交 ;提交,运行ButtonSubmit_()函数
    Gui, mainUI:Add, Button, xp+100 gButtonExit, 退出 ;结束app
    Gui, mainUI:Add, StatusBar, vGsbText ;状态栏并非默认,更新文本必须用:GuiControl, MainUI:Text, sbText, 新文本 
    Gui, mainUI:+AlwaysOnTop
    Gui, mainUI:Show, X1136 Y393
  }

  ;** Gui响应函数,以大写字母和组件类型开头
  ButtonConfigSubmit(){
    local names := StrSplit("关羽|张飞|赵云|黄忠|马超|魔法张飞|诸葛亮|张辽|貂蝉|白甲黄忠", "|")
    local i, v
    Gui, configUI:Submit, Hide
    Gui, configUI:Destroy
    roleEnglish := NAME_TABLE[Grole]
    setupHotkeys(+0)
    mainGui()
    ;让mainUI的选项框也选择之前所选人物
    for i, v in names {
      if (v == Grole) {
        GuiControl, mainUI:Choose, Grole, %i%
        break
      }
    }
    refreshSB()
  }

  ButtonMainSubmit(){
    Gui, mainUI:Submit, NoHide ; 保存用户输入后每个控件的数据,NoHide可以在提交数据后保持窗体显示
    roleEnglish := NAME_TABLE[Grole]
    switch (GwType) {
      case "一般连发": {
        wType := W_AUTOFIRE
      } case "特殊连发": {
        wType := W_SPECIAL
      } case "单发": {
        wType := W_SINGLE
      }
    }
    setupHotkeys(+1)
    refreshSB()
    MsgBox, 数据提交成功!
  }

  ButtonExit(){
    ExitApp
  }

}

/* 设置快捷键的函数与各快捷键的绑定函数
*/ {
  ;** 根据选择的exe,设置快捷键的函数
  ;again表示是否初次设定,初次设定时需要设置方向检查模块
  setupHotkeys(again := +0){
    local wTitle := "ahk_exe " . GexeTitle
    ;初次设定则安装方向检测模块与游聚平台专门的ab宏
    if (again == +0) {
      MyFaceDetector_setup(GexeTitle)
      if (wTitle == "ahk_exe X-Zone.exe"){
        Hotkey, IfWinActive, %wTitle%
        Hotkey, space, Key_Space_XZONE
        Hotkey, IfWinActive
      }
    }
    ;共通快捷键
    Hotkey, IfWinActive, %wTitle%
    Hotkey, ~r, %roleEnglish%_R
    Hotkey, ~q, %roleEnglish%_Q
    Hotkey, ~2, %roleEnglish%_2
    Hotkey, ~3, %roleEnglish%_3
    Hotkey, ~4, %roleEnglish%_3
    Hotkey, ~f, useBackItem
    Hotkey, ~t, superAutoFire_t ;超快连发,狂按时使用
    Hotkey, ~RControl, toggleLV
    Hotkey, IfWinActive
    ;设置攻击键W,情况较为特殊
    setKeyW()
  }

  ; 设置w键,根据角色和连发状态设置
  setKeyW() {
    local wTitle := "ahk_exe " . GexeTitle
    switch (wType) {
      case W_AUTOFIRE: {
        Hotkey, IfWinActive, %wTitle%
        Hotkey, ~w, normalAutoFire
        Hotkey, IfWinActive
      } case W_SPECIAL: {
        Hotkey, IfWinActive, %wTitle%
        Hotkey, ~w, specialAutoFire
        Hotkey, IfWinActive
      } case W_SINGLE: {
        Hotkey, IfWinActive, %wTitle%
        Hotkey, ~w, singleAt
        Hotkey, IfWinActive
      }
    }
  }
  ; 一般连发
  normalAutoFire() {
    press(Key_A, 50)
    sleep, 150
    while (GetKeyState("w")) {
      press(Key_A, 10)
      sleep, 10
    }
  }
  ; 单发攻击
  singleAt() {
    send, {%Key_A% down}
    sleep, 50
    send, {%Key_A% up}
    while (GetKeyState("w")) {
      sleep, 50
    }
  }
  ; t键超级连发,狂按使用
  superAutoFire_t() {
    while (GetKeyState("t")) {
      press(Key_A, 10)
      sleep, 10
    }
  }
  ; 特殊连发,避免误触招数,效果暂时不太满意
  specialAutoFire() {
    local direction := MyFaceDetector_getFace()
    local pressingDirection := GetKeyState(direction)
    if (pressingDirection) {
      send, {%direction% up}
    }
    sleep, 20
    press("down", 20)
    sleep, 20
    press(Key_A, 30)
    sleep, 20
    while (GetKeyState("w")) {
      press(Key_A, 30)
      sleep, 20
    }
  }
  
  ;专门为游聚设置的space快捷键
  Key_Space_XZONE(){
    press(MACRO_AB_XZONE)
  }
  
  ; 切换等级高低
  toggleLV(){
    if (lv == LV_LOW)
      lv := LV_HIGH
    else
      lv := LV_LOW
    refreshSB()
  }
  
  ; 一键使用背面设定物品
  useBackItem() {
    press(KEY_C, 20)
    sleep, 50
    press(KEY_B, 20)
    sleep, 50
    press(KEY_D, 30)
  }

  ;** 各角色的快捷键响应函数,函数名称为:%roleEnglish%_按键

  ;关羽快捷键
  GUANYU_Q(){
    ;press("up", 60)
    ;sleep, 20
    drSkill()
  }
  GUANYU_2(){ 
    rSkill() 
  }
  GUANYU_R(){
    dashAt(150)
  }
  GUANYU_3(){ 
    ;duSkill() ;超必杀
    ;爆气+前a击飞
    press(MACRO_ABC, 30)
    sleep, 100
    rSkill()
    ;*/
  }
  ;张飞快捷键
  ZHANGFEI_Q(){
    lrSkill()
  }
  ZHANGFEI_2(){ ;爆气必杀与跳起技能
    drSkill()
  }
  ZHANGFEI_R(){
    ;ddSkill()
    ;backDashAt()
    if (lv == LV_LOW) {
      backDashAt2() ;0-4级可用,5以上不行
    } else {
      ;dashAt() ;10级以上才可以在3a后连上
      fullHit_zhangfei("r")
    }
  }
  ZHANGFEI_3(){ ;超必杀
    duSkill()
  }
  ;赵云快捷键
  ZHAOYUN_Q(){
    duSkill()
  }
  ZHAOYUN_2(){
    ; 爆气必杀,放手时出最后一击
    drSkill()
    while (GetKeyState("2")) {
      sleep, 20
    }
    press(KEY_A, 30)
  }
  ZHAOYUN_R(){
    if (lv == LV_LOW) {
      backDashAt() ;0-4级可用,5以上不行
    } else {
      dashAt() ;10级以上才可以在3a后连上
    }
  }
  ZHAOYUN_3(){ ;超必杀
    udSkill_zhaoyun("3")
  }
  ;黄忠快捷键
  HUANGZHONG_Q(){
    drSkill()
  }
  HUANGZHONG_2(){
    rSkill()
  }
  HUANGZHONG_R(){
    dashAt()
  }
  HUANGZHONG_3(){ ;超必杀
    udSkill()
  }
  ;马超快捷键
  MACHAO_Q(){
    udSkill()
  }
  MACHAO_2(){
    rSkill("2")
  }
  MACHAO_R(){ 
    ;lrSkill() ;爆气必杀
    ;dashAt()
    fullHit_machao("r")
  }
  MACHAO_3(){ ;超必杀
    duSkill()
  }
  ;魔法张飞快捷键
  MOZHANG_Q(){
    lrSkill()
  }
  MOZHANG_2(){
    drSkill()
  }
  MOZHANG_R(){ 
    if (lv == LV_LOW) {
      backDashAt2() ;0-4级可用,5以上不行
    } else {
      ;dashAt() ;10级以上才可以在3a后连上
      fullHit_zhangfei("r")
    }
  }
  MOZHANG_3(){ 
     backTurnAt("3") ;转身连
  }
  ;诸葛亮快捷键
  ZHUGELIANG_Q(){
    if (lv == LV_LOW) {
      lrSkill()
    } else {
      fullHit_zhugeliang("q")
    }
  }
  ZHUGELIANG_2(){
    ;backDashAt()
    drSkill()
  }
  ZHUGELIANG_R(){
    ;dashAt()
    backDashAt()
  }
  ZHUGELIANG_3(){ ;超必杀
    duSkill()
  }
  ;张辽快捷键
  ZHANGLIAO_Q(){
    lrSkill()
  }
  ZHANGLIAO_2(){ 
    drSkill()
    ;rSkill("2")
    ;squatHit(0)
  }
  ZHANGLIAO_R(){
    ;dashAt()
    if (lv == LV_LOW) {
      rSkill("r")
    } else {
      fullHit_zhangliao("r")
    }
  }
  ZHANGLIAO_3(){ ;超必杀
    duSkill()
  }
  ;貂蝉快捷键
  DIAOCHAN_Q(){
    drSkill()
  }
  DIAOCHAN_2(){
    squatHit(350)
  }
  DIAOCHAN_R(){
    udSkill("r")
  }
  DIAOCHAN_3(){ ;超必杀
    duSkill() 
  }
  ;白甲黄忠快捷键
  BAIHUANG_Q(){
    drSkill()
  }
  BAIHUANG_2(){
    rSkill()
    ;duSkill() ;爆气必杀
    ;dashAt()
  }
  BAIHUANG_R(){
    if (lv == LV_LOW) {
      ;backDashAt() ;0-4级可用,5以上不行
      backDashAt2() ;0-4级可用,5以上不行
    } else {
      ;dashAt() ;10级以上才可以在3a后连上
      fullHit_baihuang("r") ;10级以上完全连段前2招
    }
    ;backDashAt() ;0-4级用,5以上需要先撞连
    ;backDashAt2()
  }
  BAIHUANG_3(){ ;超必杀
    udSkill()
  }

}

/* 运行脚本
*/
configGui()
return
